#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <float.h>

/****************** Constantes *****************/
#define CANTIDAD_PALABRAS_RESERVADAS 13
#define CANTIDAD_MAX_TS	1000
#define ESTADO_INICIAL 0
#define ESTADO_FINAL 39
#define LARGO_MAX_TOKEN 35
#define LARGO_MAX_TOKEN_EXT 45
#define TAM_MAX_TOKENS 5000
#define TAM_MAX_CADENA 30
#define TAM_MAX_VAR 20
#define TRUE 1
#define FALSE 0

/****************** Tipos de Tokens *****************/
#define CONSTANTE_STRING			1
#define CONSTANTE_NUMERICA			2
#define PUNTO_Y_COMA				3
#define DOS_PUNTOS 					4
#define COMA	 					5
#define INI_CORCHETE				6
#define FIN_CORCHETE				7
#define INI_PARENTESIS				8
#define FIN_PARENTESIS				9
#define INI_LLAVE					10
#define FIN_LLAVE					11
#define COMILLA						12
#define CADENA						13
#define AND		 				 	14
#define OR		  					15
#define NEGACION		  			16
#define MAYOR  						17
#define MAYOR_IGUAL					18
#define MENOR  						19
#define MENOR_IGUAL					20
#define IGUAL_IGUAL					21
#define DISTINTO					22
#define SUMA  		 				23
#define RESTA  						24
#define MULTIPLICACION 				25
#define DIVISION  					26
#define IGUAL  						27
#define VARIABLE					28
#define DEFINE 						29
#define ENDDEFINE  					30
#define REAL 						31
#define ENTERO 					  	32
#define STRING 					  	33
#define WHILE						34
#define END_WHILE					35
#define IF					 		36
#define END_IF						37
#define PRINT 	 					38
#define RENAME						39
#define ROUND						40
#define TRUNC						41

/****************** Nros de columna para matriz de estados *****************/
#define COLUMNA_LETRA				 0
#define COLUMNA_DIGITO			 	 1
#define COLUMNA_SIMBOLO			 	 2
#define COLUMNA_PUNTO			 	 3
#define COLUMNA_DIVISION		 	 4
#define COLUMNA_NEGACION		 	 5
#define COLUMNA_COMILLAS		 	 6
#define COLUMNA_AND		     	  	 7
#define COLUMNA_OR		       		 8
#define COLUMNA_MENOR			 	 9
#define COLUMNA_MAYOR			 	 10
#define COLUMNA_IGUAL			 	 11
#define COLUMNA_SUMA			     12
#define COLUMNA_RESTA			 	 13
#define COLUMNA_MULTIPLICACION 	 	 14
#define COLUMNA_PUNTO_Y_COMA  	     15
#define COLUMNA_COMA			     16
#define COLUMNA_INI_BLOQUE		 	 17
#define COLUMNA_FIN_BLOQUE		 	 18
#define COLUMNA_INI_CORCHETE		 19
#define COLUMNA_FIN_CORCHETE		 20
#define COLUMNA_INI_PARENTESIS	 	 21
#define COLUMNA_FIN_PARENTESIS	     22
#define COLUMNA_DOS_PUNTOS 	 		 23
#define COLUMNA_BLANCO		 	 	 24 //Resume el espacio, tab, enter y escape.

/****************** Rutinas semanticas *****************/
void iniVar();
void contVar();
void finVar();
void iniCteNum();
void contCteNum();
void finCteNum();
void iniCteString();
void contCteString();
void finCteString();
void error();
void opDivision();
void opNegacion();
void iniAnd();
void contAnd();
void finAnd();
void iniOr();
void contOr();
void finOr();
void opMenor();
void opMayor();
void opIgual();
void opSuma();
void opResta();
void opMultiplicacion();
void puntoComa();
void coma();
void iniBloque();
void finBloque();
void iniCorchete();
void finCorchete();
void iniParentesis();
void finParentesis();
void dos_puntos();
void nada();
void compIgual();
void opMenorIgual();
void opMayorIgual();
void opDistinto();
void iniComent();
void contComent();
void posFinComent();
void finComent();
void posIniComent2();
void iniComent2();
void contComent2();
void posFinComent2();
void finComent2();
void puntoYComa();
void dosPuntos();
void opIgualIgual();
void iniAnd();
void finAnd();
void iniOr();
void finOr();

/****************** Funcion generica *****************/
void completarToken(int, int);
void analizarLexico(char *);
int inicializacion(char *);
FILE* abrirArchivo(char*, char);
int perteneceALaLista(char*, char );
void inicializarCadena();
void imprimirTablaSimbolos();
void imprimirTokens();
void convertirToken(int , char* , char*);

/****************** Estructuras *****************/
struct strTablaSimbolos {
    char nombre[LARGO_MAX_TOKEN_EXT];
    char tipo[15];
    char valor[30];
    int longitud;
};
struct strTokens {
    int tipo;
    char valor[LARGO_MAX_TOKEN];
};
struct strPalabrasReservadas {
	char palabra[LARGO_MAX_TOKEN_EXT];
	int numero;
};

/****************** Variables Globales *****************/
char cadena[TAM_MAX_CADENA];
FILE *fuente;
struct strTablaSimbolos tablaSimbolos[CANTIDAD_MAX_TS];
struct strTokens listaTokens[TAM_MAX_TOKENS];
struct strPalabrasReservadas reservadas[CANTIDAD_PALABRAS_RESERVADAS];
char caracterLeido;
int tipoToken;
int yylval;
int cantCaracteres;
char tokenGenerado[LARGO_MAX_TOKEN];
int tipoToken;
int cantTokens;
int leido;
int cantComentariosAbiertos;
int posUltimoSimbolo;
int lineaLeida = 1;
char generando[TAM_MAX_CADENA];

/****************** Arrays Globales *****************/
char letras[] = {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','\0'};
char digitos[] = {'0','1','2','3','4','5','6','7','8','9','\0'};
char simbolos[] = {'@','#','%','$','?','~','^','\0'};
char blancos[] = {'\n','\t','\r',' ',EOF,'\0'};

/***************** MATRICES *****************/
int nuevoEstado[37][26] = {
{1,2,36,3,6,34,10,12,14,16,19,21,23,24,25,26,27,28,29,30,31,32,33,35,0},
{1,1,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36},
{36,2,36,3,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36},
{36,3,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36},
{5,5,5,5,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5},
{5,5,5,5,7,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5},
{36,36,36,36,36,5,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36},
{5,5,5,5,7,8,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5},
{8,8,8,8,8,9,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8},
{8,8,8,8,5,9,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8},
{10,10,10,10,10,10,11,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10},
{36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36},
{36,36,36,36,36,36,36,13,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36},
{36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36},
{36,36,36,36,36,36,36,36,15,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36},
{36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36},
{36,36,36,36,36,36,36,36,36,36,17,18,36,36,36,36,36,36,36,36,36,36,36,36,36},
{36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36},
{36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36},
{36,36,36,36,36,36,36,36,36,36,36,20,36,36,36,36,36,36,36,36,36,36,36,36,36},
{36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36},
{36,36,36,36,36,36,36,36,36,36,36,22,36,36,36,36,36,36,36,36,36,36,36,36,36},
{36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36},
{36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36},
{36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36},
{36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36},
{36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36},
{36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36},
{36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36},
{36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36},
{36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36},
{36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36},
{36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36},
{36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36},
{36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36},
{36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
};

void (*proceso[37][26])()= {
{iniVar,iniCteNum,error,iniCteNum,opDivision,opNegacion,iniCteString,iniAnd,iniOr,opMenor,opMayor,opIgual,opSuma,opResta,opMultiplicacion,puntoYComa,coma,iniBloque,finBloque,iniCorchete,finCorchete,iniParentesis,finParentesis,dosPuntos,nada},
{contVar,contVar,finVar,finVar,finVar,finVar,finVar,finVar,finVar,finVar,finVar,finVar,finVar,finVar,finVar,finVar,finVar,finVar,finVar,finVar,finVar,finVar,finVar,finVar,finVar,finVar},
{finCteNum,contCteNum,finCteNum,contCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum},
{finCteNum,contCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum},
{contComent,contComent,contComent,contComent,finComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent},
{contComent,contComent,contComent,contComent,posIniComent2,posFinComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent},
{nada,nada,nada,nada,nada,iniComent,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada},
{contComent,contComent,contComent,contComent,posIniComent2,iniComent2,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent},
{contComent2,contComent2,contComent2,contComent2,contComent2,posFinComent2,contComent2,contComent2,contComent2,contComent2,contComent2,contComent2,contComent2,contComent2,contComent2,contComent2,contComent2,contComent2,contComent2,contComent2,contComent2,contComent2,contComent2,contComent2,contComent2},
{contComent2,contComent2,contComent2,contComent2,finComent2,posFinComent2,contComent2,contComent2,contComent2,contComent2,contComent2,contComent2,contComent2,contComent2,contComent2,contComent2,contComent2,contComent2,contComent2,contComent2,contComent2,contComent2,contComent2,contComent2,contComent2},
{contCteString,contCteString,contCteString,contCteString,contCteString,contCteString,contCteString,contCteString,contCteString,contCteString,contCteString,contCteString,contCteString,contCteString,contCteString,contCteString,contCteString,contCteString,contCteString,contCteString,contCteString,contCteString,contCteString,contCteString,contCteString},
{finCteString,finCteString,finCteString,finCteString,finCteString,finCteString,finCteString,finCteString,finCteString,finCteString,finCteString,finCteString,finCteString,finCteString,finCteString,finCteString,finCteString,finCteString,finCteString,finCteString,finCteString,finCteString,finCteString,finCteString,finCteString},
{error,error,error,error,error,error,error,finAnd,error,error,error,error,error,error,error,error,error,error,error,error,error,error,error,error,error},
{nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada},
{error,error,error,error,error,error,error,error,finOr,error,error,error,error,error,error,error,error,error,error,error,error,error,error,error,error},
{nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada},
{nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,opDistinto,opMenorIgual,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada},
{nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada},
{nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada},
{nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,opMayorIgual,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada},
{nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada},
{nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,opIgualIgual,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada},
{nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada},
{nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada},
{nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada},
{nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada},
{nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada},
{nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada},
{nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada},
{nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada},
{nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada},
{nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada},
{nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada},
{nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada},
{nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada},
{nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada},
{nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada}
};


/***************** PROGRAMA *****************/
int main(int argc, char *argv[]) {
	char nombreArchivo[200] = "prueba.txt";

  /*  if(argc != 2) {
        exit(printf("ERROR: Solo puede recibir 1 parametro. \nUso: analex [nombre_archivo]"));
    }else{
       strcpy(nombreArchivo, argv[1]);
   }  */
	 analizarLexico(nombreArchivo);
  	 imprimirTokens();
  	 imprimirTablaSimbolos();
    return EXIT_SUCCESS;
}

void analizarLexico(char* nombreArchivo) {

	if(inicializacion(nombreArchivo) == 1 ) {
     	 exit(printf("ERROR: No se pudo abrir el archivo fuente.\n"));
   }

   while(!feof(fuente)){
		if(leido == FALSE) {
      	caracterLeido = (char)getc(fuente);
         // suma las lineas del archivo ingresado
			if (caracterLeido == '\n') {
				lineaLeida++;
			}
		}
		// Carga el tipo de Token
		listaTokens[cantTokens].tipo = yylex();
		if (listaTokens[cantTokens].tipo != 0) {
     		//Carga el codigo de Token
    		strcpy(listaTokens[cantTokens].valor, tokenGenerado);
  	  		//Se incrementa el contador de tokens
     	  	cantTokens++;
   	}
	}
  	fclose(fuente);
}

int inicializacion(char * nombreArchivo) {

   if ((fuente = abrirArchivo(nombreArchivo,'L')) == NULL) {
        return EXIT_FAILURE;
   }

    // Inicializa la lista de palabras reservadas
	strcpy(reservadas[0].palabra, "DEFINE");
	reservadas[0].numero = DEFINE  ;
	strcpy(reservadas[1].palabra, "ENDDEFINE");
	reservadas[1].numero = ENDDEFINE;
	strcpy(reservadas[2].palabra, "REAL");
	reservadas[2].numero = REAL;
	strcpy(reservadas[3].palabra, "ENTERO");
	reservadas[3].numero = ENTERO;
	strcpy(reservadas[4].palabra, "STRING");
	reservadas[4].numero = STRING;
	strcpy(reservadas[5].palabra, "WHILE");
	reservadas[5].numero = WHILE;
	strcpy(reservadas[6].palabra, "ENDWHILE");
	reservadas[6].numero = END_WHILE;
	strcpy(reservadas[7].palabra, "IF");
	reservadas[7].numero = IF;
	strcpy(reservadas[8].palabra, "ENDIF");
	reservadas[8].numero = END_IF;
	strcpy(reservadas[9].palabra, "PRINT");
	reservadas[9].numero = PRINT;
	strcpy(reservadas[10].palabra, "RENAME");
	reservadas[10].numero = RENAME;
    strcpy(reservadas[11].palabra, "ROUND");
	reservadas[11].numero = ROUND;
	strcpy(reservadas[12].palabra, "TRUNC");
	reservadas[12].numero = TRUNC;

   cantTokens = 0;
   cantCaracteres = 0;
   cantComentariosAbiertos = 0;
   posUltimoSimbolo = 0;
   inicializarCadena();

   return EXIT_SUCCESS;
}

FILE* abrirArchivo (char* nombreArchivo, char modo) {
    if (modo == 'L') {
        return (fopen (nombreArchivo, "r"));
    }
    return (fopen (nombreArchivo, "w"));
}

void inicializarCadena() {
    int i;
    for(i = 0; i < TAM_MAX_CADENA; i++) {
        cadena[i] = '\0';
        generando[i] = '\0';
    }
}

int getEvent(char caracterLeido) {

  	if (perteneceALaLista(letras, caracterLeido )) {
     // printf("COLUMNA_LETRA\n");
		return(COLUMNA_LETRA);
	} else if (perteneceALaLista(digitos, caracterLeido)) {
      //printf("COLUMNA_DIGITO\n");
		return(COLUMNA_DIGITO);
	} else if (perteneceALaLista(simbolos , caracterLeido)) {
      //printf("COLUMNA_SIMBOLO\n");
		return(COLUMNA_SIMBOLO);
	} else if (perteneceALaLista(blancos, caracterLeido)) {
      //printf("COLUMNA_BLANCO\n");
		return(COLUMNA_BLANCO);
	}

	//Resto de los caracteres
	switch(caracterLeido) {
		case '+' :  {//printf("COLUMNA_SUMA\n");
                 	  	return(COLUMNA_SUMA);}
		case '-' :  {//printf("COLUMNA_RESTA\n");
                  	return(COLUMNA_RESTA);}
		case '*' :  {//printf("COLUMNA_MULTIPLICACION\n");
                  	return(COLUMNA_MULTIPLICACION);}
		case '/' :  {//printf("COLUMNA_DIVISION\n");
           		      return(COLUMNA_DIVISION);}
		case ';' :  {//printf("COLUMNA_PUNTO_Y_COMA\n");
               		return(COLUMNA_PUNTO_Y_COMA);}
		case ',' :	{//printf("COLUMNA_COMA\n");
              		   return(COLUMNA_COMA);}
  		case '.' :	{//printf("COLUMNA_PUNTO\n");
                  	return(COLUMNA_PUNTO);}
		case '"' :	{//printf("COLUMNA_COMILLAS\n");
                  	return(COLUMNA_COMILLAS);}
		case '>' :	{//printf("COLUMNA_MAYOR\n");
                  	return(COLUMNA_MAYOR);}
		case '<' :	{//printf("COLUMNA_MENOR\n");
                  	return(COLUMNA_MENOR);}
		case '=' :	{//printf("COLUMNA_IGUAL\n");
                  	return(COLUMNA_IGUAL);}
		case '(' :	{//printf("COLUMNA_INI_PARENTESIS\n");
                  	return(COLUMNA_INI_PARENTESIS);}
		case ')' :	{//printf("COLUMNA_FIN_PARENTESIS\n");
                  	return(COLUMNA_FIN_PARENTESIS);}
		case '{' :	{//printf("COLUMNA_INI_BLOQUE\n");
                  	return(COLUMNA_INI_BLOQUE);}
		case '}' :	{//printf("COLUMNA_FIN_BLOQUE\n");
                  	return(COLUMNA_FIN_BLOQUE);}
		case '[' :  {//printf("COLUMNA_INI_CORCHETE\n");
                  	return(COLUMNA_INI_CORCHETE);}
		case ']' :	{//printf("COLUMNA_FIN_CORCHETE\n");
                 		return(COLUMNA_FIN_CORCHETE);}
		case ':' :	{//printf("COLUMNA_DOS_PUNTOS\n");
                  	return(COLUMNA_DOS_PUNTOS);}
		case '!' :	{//printf("COLUMNA_NEGACION\n");
                  	return(COLUMNA_NEGACION);}
      case '&' :	{//printf("COLUMNA_AND\n");
                  	return(COLUMNA_AND);}
      case '|' :	{//printf("COLUMNA_OR\n");
                  	return(COLUMNA_OR);}
  	}

	//Caracter no admitido por el lenguaje. Cortar Proceso.
  	exit(printf("ERROR ANALEX: Caracter '%c' no permitido.", caracterLeido));
}

int yylex() {
    //Inicializo variables por cada nuevo token
	int estado = ESTADO_INICIAL;
	int columna = -1;
	yylval = -1;
	tipoToken = 0;
   leido = FALSE;

	while (!feof(fuente) && estado != ESTADO_FINAL) {
		columna = getEvent(caracterLeido);

      (proceso[estado][columna])();
		estado = nuevoEstado[estado][columna];

    	if(leido == FALSE) {
      	caracterLeido = (char)getc(fuente);
         // suma las lineas del archivo ingresado
			if (caracterLeido == '\n') {
				lineaLeida++;
			}
     	}
	}

	if(feof(fuente)) {
		columna = getEvent(caracterLeido);
		(proceso[estado][columna])();
		estado = nuevoEstado[estado][columna];
       //Verifica si los comentarios se encuentran correctamnete cerrados
       if(cantComentariosAbiertos > 0) {
			exit(printf("ERROR ANALEX: Varifique comentarios.\n"));
		}
	}

	return tipoToken;
}



int perteneceALaLista(char* lista, char caracterLeido) {
   int i;
   for (i=0;lista[i] != '\0'; i++){
	    if (lista[i] == caracterLeido) {
				return 1;
		 }
   }
	return 0;
}

int esPalabraReservada(char *c) {
	int i;
	for (i = 0; i < CANTIDAD_PALABRAS_RESERVADAS; i++) {
		// Compara las palabras, IMPLEMENTAR CASE SENSITIVE
	 	if (strcmp(reservadas[i].palabra, c) == 0) {
 		  return reservadas[i].numero;
	 	}
	}
	return FALSE;
}

void imprimirTokens() {
  	FILE *fileTokens;
	char tokenFormateado[LARGO_MAX_TOKEN_EXT];
	int i;
	 //Abrir archivo para guardar la lista de tokens
   if((fileTokens = abrirArchivo("ListaTokens.txt",'E')) == NULL) {
         printf("ERROR: No se pudo abrir el archivo de salida de tokens.\n");
	}

   printf("Lista de Tokens\n");
	for(i = 0; i < cantTokens; i++){
		convertirToken(listaTokens[i].tipo, listaTokens[i].valor, tokenFormateado);
      if(i == cantTokens - 1){
      	//Ultimo token
         printf("%s", tokenFormateado);
         fprintf(fileTokens, "%s", tokenFormateado); // Guardar en archivo
      } else {
      	printf("%s, ", tokenFormateado); //Pantalla
         fprintf(fileTokens, "%s, ", tokenFormateado); // Guardar en archivo
      }
    }
    fclose(fileTokens);
}

void imprimirTablaSimbolos() {
 	FILE *fileSimbolos;
	int i;

   //Abrir archivo para guardar la tabla de simbolos
   if((fileSimbolos = abrirArchivo("TablaSimbolos.txt",'E')) == NULL) {
   	printf("ERROR: No se pudo abrir el archivo de salida de la tabla de simbolos.\n");
	}
   //Imprime la tabla de simbolos y guarda en archivo de salida
   printf("\n\nTabla de Simbolos\n");
   printf("%s\t\t\t\t%s\t\t%s\t\t%s\n", "Nombre", "Tipo", "Valor", "Longitud");
   fprintf(fileSimbolos, "%s\t\t\t\t%s\t\t%s\t\t%s\n", "Nombre", "Tipo", "Valor", "Longitud");
   for(i = 0; i < posUltimoSimbolo; i++) {
		if(tablaSimbolos[i].longitud > 0) {
			printf("%s\t\t\t\t%s\t\t%s\t\t%d\n", tablaSimbolos[i].nombre, "-", "-" , tablaSimbolos[i].longitud);
			fprintf(fileSimbolos, "%s\t\t\t%s\t\t%s\t\t%d\n", tablaSimbolos[i].nombre, "-", "-", tablaSimbolos[i].longitud);
    	} else {
			printf("%s\t\t\t\t%s\t\t%s\t\t%s\n", tablaSimbolos[i].nombre, "-", "-" ,"-");
			fprintf(fileSimbolos, "%s\t\t\t\t%s\t\t%s\t\t%s\n", tablaSimbolos[i].nombre, "-", "-", "-");
    	}
    }
    fclose(fileSimbolos);
}

int agregarTS(struct strTablaSimbolos simbolo) {

	//Se comprueba que el simbolo no exista
   if ((yylval = buscarTS(simbolo.nombre)) != -1) {
   	return yylval; //Ya existe, no se agrega
	}
	//Se agrega a la tabla
   tablaSimbolos[posUltimoSimbolo] = simbolo;
	//Se guarda la posicion donde se agrego
   yylval = posUltimoSimbolo;
	//Se incrementa el contador de simbolos
	posUltimoSimbolo++;
  	return (posUltimoSimbolo-1);
}

int buscarTS(char *simbolo) {
 	int i;
  	for (i = 0; i < posUltimoSimbolo; i++) {
 		if (strcmp(tablaSimbolos[i].nombre, simbolo) == 0) {
   			return(i);
		}
	}
 	return (-1);
}

void convertirToken(int tipoToken, char *valor, char *salida) {
	int i;
	//Inicializa la salida
   for(i = 0; i < LARGO_MAX_TOKEN_EXT; i++) {
		salida[i] = '\0';
	}
  	salida[0] = '<';
  	salida[1] = ' ';
	if(tipoToken == VARIABLE) {
		//Variable
		strcat(salida, "ID:");
		strcat(salida, valor);
//	} else if(VAR <= tipoToken && ALLEQ >= tipoToken) {
      //Palabra reservada
//		strcat(salida, "RSV:");
 //     strcat(salida, valor);
	} else {
     	//Otro
  		strcat(salida, valor);
	}
   strcat(salida, " >");
}

void iniVar() {
	//  printf(" \n iniVar,");
	cantCaracteres = 1;
	inicializarCadena();
  	strcpy(generando, "Variable o Palabra Reservada");
	cadena[cantCaracteres-1] = caracterLeido;
}

void contVar() {
	//  printf(" contVar,");
	cantCaracteres++;
	cadena[cantCaracteres-1] = caracterLeido;
}

void finVar() {
	//  printf("finVar \n");
   struct strTablaSimbolos simbolo;
   tipoToken = VARIABLE;
  	leido = TRUE; //Indica que no debe leerse otro caracter

	//Se verifica si es una palabra reservada
  	if((tipoToken = esPalabraReservada(cadena)) != 0) {
		strcpy(tokenGenerado, cadena);
  		return; //Se vuelve, no hay que agregar a la TS
	}
	if (cantCaracteres > TAM_MAX_VAR) {
		exit(printf("\nERROR ANALEX: La variable '%s' excede la cantidad maxima de caracteres permitidos.\n", cadena));
	}
	strcpy(tokenGenerado, cadena);
	//Agregar a TS
	strcpy(simbolo.nombre, tokenGenerado);
	strcpy(simbolo.tipo, "ID");
	strcpy(simbolo.valor, "");
	simbolo.longitud = 0;
	agregarTS(simbolo);
}

void iniCteNum() {
  // printf("\n iniCteNum,");
  	cantCaracteres = 1;
	inicializarCadena();
   strcpy(generando, "Constante Numerica");
	cadena[cantCaracteres-1] = caracterLeido;
}

void contCteNum() {
   //printf(" iniCteNum,");
  	cantCaracteres++;
	if(cantCaracteres == TAM_MAX_CADENA) {
		exit(printf("ERROR ANALEX: El valor '%s' esta fuera del rango numerico permitido. \n", cadena));
	}
	cadena[cantCaracteres-1] = caracterLeido;
}

void finCteNum() {
   //printf("f inCteNum\n");
   struct strTablaSimbolos simbolo;
   tipoToken = CONSTANTE_NUMERICA;
   leido = TRUE; //Indica que no debe leerse otro caracter
	strcpy(tokenGenerado, cadena);

	//	Agregar a TS
  	strcpy(simbolo.nombre, tokenGenerado);
	strcpy(simbolo.tipo, "CONSTANTE_NUMERICA");
	strcpy(simbolo.valor, tokenGenerado);
	simbolo.longitud = 0;

	agregarTS(simbolo);
}

void iniCteString() {
   //printf("\n iniCteString,");
   cantCaracteres = 1;
	inicializarCadena();
   strcpy(generando, "Constante String");
	cadena[cantCaracteres-1] = caracterLeido;
}

void contCteString() {
   //printf(" contCteString,");
  	cantCaracteres++;

	if (cantCaracteres == TAM_MAX_CADENA) {
			exit(printf("ERROR ANALEX: La constante '%s' excede la cantidad maxima de caracteres permitidos.\n", cadena));
	}
	cadena[cantCaracteres-1] = caracterLeido;
}

void finCteString() {
   //printf("finCteString\n");
   struct strTablaSimbolos simbolo;
   tipoToken = CONSTANTE_STRING;
   strcpy(tokenGenerado, cadena);

   //Agregar a TS
   strcpy(simbolo.nombre, tokenGenerado);
   strcpy(simbolo.tipo, "CONSTANTE_STRING");
   strcpy(simbolo.valor, tokenGenerado);
   simbolo.longitud = 0;
	agregarTS(simbolo);
   leido = TRUE; //Indica que no debe leerse otro caracter
}

void opSuma() {
   //printf("opSuma\n");
	completarToken(1, SUMA);
}

void opResta() {
   //printf("opResta\n");
  	completarToken(1, RESTA);
}

void opMultiplicacion() {
   //printf("opMultiplicacion\n");
	completarToken(1, MULTIPLICACION);
}

void opDivision() {
   //printf("opDivision\n");
	completarToken(1, DIVISION);
}

void iniBloque() {
   //printf("iniBloque\n");
  	completarToken(1, INI_LLAVE);
}

void finBloque() {
   //printf("finBloque\n");
	completarToken(1, FIN_LLAVE);
}

void iniCorchete() {
   //printf("iniCorchete\n");
  	completarToken(1, INI_CORCHETE);
}

void finCorchete() {
   //printf("finCorchete\n");
  	completarToken(1, FIN_CORCHETE);
}

void iniParentesis() {
	// printf("iniParentesis\n");
  	completarToken(1, INI_PARENTESIS);
}

void finParentesis() {
   //printf("finParentesis\n");
	completarToken(1, FIN_PARENTESIS);
}

void puntoComa() {
	// printf("puntoComa\n");
  	completarToken(1, PUNTO_Y_COMA);
}

void coma() {
   //printf("coma\n");
  	completarToken(1, COMA);
}

void dosPuntos() {
   //printf("dosPuntos\n");
	completarToken(1, DOS_PUNTOS);
}

void opNegacion() {
   //printf("opNegacion\n");
	completarToken(1, NEGACION);
}

void opIgual() {
	// printf("opIgual\n");
	completarToken(1, IGUAL);
}

void opMayor() {
   //printf("opMayor\n");
	completarToken(1, MAYOR);
}

void opMenor() {
   //printf("opMenor\n");
  	completarToken(1, MENOR);
}

void igualIgual() {
	// printf("igualIgual\n");
  	completarToken(2, IGUAL_IGUAL);
}

void opMayorIgual() {
	// printf("opMayorIgual\n");
	completarToken(2, MAYOR_IGUAL);
}

void opMenorIgual() {
	//printf("opMenorIgual\n");
	completarToken(2, MENOR_IGUAL);
}

void opDistinto() {
	//printf("opDistinto\n");
	completarToken(2, DISTINTO);
}

void puntoYComa(){
	//	printf("puntoYComa\n");
   completarToken(1, PUNTO_Y_COMA);
}

void opIgualIgual(){
	//printf("opIgualIgual\n");
	completarToken(2, IGUAL_IGUAL);
}

void iniAnd(){
	//printf("iniAnd\n");
   strcpy(generando, "Operador And");
	completarToken(1, AND);
}

void finAnd(){
	//printf("finAnd\n");
 	completarToken(2, AND);
}

void iniOr(){
	//printf("iniOr\n");
   strcpy(generando, "Operador And");
	completarToken(1, OR);
}

void finOr(){

	// printf("finOr\n");

 	completarToken(2, OR);

}

void completarToken(int cantCarac, int tipo) {
	// printf("completarToken\n");
	tipoToken = tipo;
  	if(cantCarac == 1) {
		inicializarCadena();
	}
	cantCaracteres = cantCarac;

	cadena[cantCaracteres-1] = caracterLeido;
	strcpy(tokenGenerado, cadena);
}

void nada() {
   //printf("nada, ");
 	if (leido == TRUE) {
		leido = FALSE;
	} else {
	   leido = TRUE;
	}
}

void error() {
  //	printf("error\n");
   if(strcmp(generando,"") != 0){
      exit(printf("ERROR ANALEX: Generando %s, Linea %d\n.", generando, lineaLeida));
  }else{
    	exit(printf("ERROR ANALEX: Linea %d\n", lineaLeida, caracterLeido));
   }
}

void iniComent() {
   //printf("iniComent\n");
  	tipoToken = 0; //Limpio el tipoToken seteado por opDiv

  	cantComentariosAbiertos++; //Se abre un bloque

	if(cantComentariosAbiertos > 1) {
		exit(printf("ERROR ANALEX: Error al crear comentario.\n"));
	}
}

void contComent() {
   //printf("contComent\n");
	//Nada
}

void posFinComent() {
   // printf("posFinComent\n");
	//Nada
}

void finComent() {
	//printf("finComent\n");
 	cantComentariosAbiertos--; //Se cierra un bloque

	if (cantComentariosAbiertos > 0) {
		exit(printf("ERROR ANALEX: Error al crear comentario.\n"));
	}
}

void posIniComent2() {
	//printf("posIniComent2\n");
	//Nada
}

void iniComent2() {
	// printf("iniComent2\n");
  	cantComentariosAbiertos++; //Se abre un bloque

	if(cantComentariosAbiertos > 2) {
		exit(printf("ERROR ANALEX: Error al crear comentario de segundo nivel.\n"));
	}
}

void contComent2() {
	//printf("contComent2\n");
	//Nada
}

void posFinComent2() {
	//printf("posFinComent2\n");
	//Nada
}

void finComent2() {
   //printf("finComent2\n");
  	cantComentariosAbiertos--; //Se cierra un bloque

	if (cantComentariosAbiertos > 1) {
		exit(printf("ERROR ANALEX: Error al crear comentario de segundo nivel.\n"));
	}
}

